#ifndef __BLOCK_QUEUE_HPP__
#define __BLOCK_QUEUE_HPP__

#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>

template <typename T>
class BlockQueue
{
    private:
    bool IsFull()
    {
        return _blockqueue.size() == _cap;
    }
    bool IsEmpty()
    {
        return _blockqueue.empty();
    }
public:
BlockQueue(int cap)
:_cap(cap)
{
    _product_wait_num = 0;
    _consum_wait_num = 0;
    pthread_mutex_init(&_mutex,nullptr);
    pthread_cond_init(&_consum_cond,nullptr);
    pthread_cond_init(&_product_cond,nullptr);
}

~BlockQueue()
{
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_consum_cond);
    pthread_cond_destroy(&_product_cond);
}
//生产者是向阻塞队列里面加数据
void Enqueue(T & in)
{
    pthread_mutex_lock(&_mutex);
    //生产者拿到了队列，判断队列是否为满的
    //如果是满的，则需要通知消费者来消费，让后让该生产者去等待
    
    while(IsFull())//为什么是while而不是if，保证唤醒的进程争夺锁成功后，要确保队列中有数据再去执行后面的代码
    {
        _product_wait_num++;//++和--操作

        pthread_cond_wait(&_product_cond,&_mutex);
        _product_wait_num--;
    }
    //生产
    _blockqueue.push(in);
    if(_consum_wait_num > 0)
    {
        pthread_cond_signal(&_consum_cond);
    }
    pthread_mutex_unlock(&_mutex);

}
//消费者是从队列里面拿数据
void Pop(T * out)
{
    pthread_mutex_lock(&_mutex);

    while(IsEmpty())
    {
        //如果队列为空，消费者就去等待，同时释放锁
        _consum_wait_num++;

        pthread_cond_wait(&_consum_cond,&_mutex);
        _consum_wait_num--;
    }

    //消费
    *out = _blockqueue.front();
    _blockqueue.pop();
    if(_product_wait_num > 0)
    {
        pthread_cond_signal(&_product_cond);
    }
    pthread_mutex_unlock(&_mutex);
}
private:

std::queue<T> _blockqueue;
int _cap;
pthread_mutex_t _mutex;//保护阻塞队列的锁
pthread_cond_t _consum_cond;
pthread_cond_t _product_cond;

int _product_wait_num;
int _consum_wait_num;

};


#endif